/*
 * (C) 2014-2015 Alibaba Group Holding Limited
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 *
 *     __  ___   ______        ___       __          ___
 *    |  |/  /  /  __  \      /   \     |  |        /   \
 *    |  '  /  |  |  |  |    /  ^  \    |  |       /  ^  \
 *    |    <   |  |  |  |   /  /_\  \   |  |      /  /_\  \
 *    |  .  \  |  `--'  |  /  _____  \  |  `----./  _____  \
 *    |__|\__\  \______/  /__/     \__\ |_______/__/     \__\
 *
 *
 *
 */
//
// Created by KOALA TEAM on 12/19/14.
//

#import "KLRouter.h"


typedef NS_ENUM(NSInteger, KLRootVCType){
    KLRootVCTypeNormal,
    KLRootVCTypeNavi
};

static NSDictionary  * _klUriRoute = nil;




@interface KLURL:NSObject

@property(nonatomic,strong)NSString     *key;
@property(nonatomic,strong)NSDictionary *params;
- (instancetype)initWithURL:(NSURL*)url;

@end
@implementation KLURL
- (instancetype)initWithURL:(NSURL*)url{
    if(self = [super init]){
        NSString *path = [[url pathComponents] lastObject];
        _key = path?path:[url host];
        _params = [self parseURIQueryString:[url query]];

    }
    return self;
}
- (NSDictionary*) parseURIQueryString:(NSString*)query{
    NSMutableDictionary* param = [[NSMutableDictionary alloc] initWithCapacity:2];
    NSArray* array = [query componentsSeparatedByString:@"&"];
    for(NSString* ss in array){
        NSArray* key = [ss componentsSeparatedByString:@"="];
        
        switch ([key count]) {
            case 1:
                [param setValue:nil forKey:[key objectAtIndex:0]];
                break;
            case 2:
                [param setValue:[key objectAtIndex:1] forKey:[key objectAtIndex:0]];
                break;
            default:
                break;
        }
    }
    return param;
}
@end

@interface KLTopViewController:NSObject
@property(nonatomic,assign)KLRootVCType rootVCType;
@property(nonatomic,strong)UIViewController *topViewController;

- (instancetype) initWith:(UIViewController*)viewController rootType:(KLRootVCType)type;
- (void) display:(UIViewController*)viewController;

@end

@implementation KLTopViewController
- (instancetype) initWith:(UIViewController*)topViewController rootType:(KLRootVCType)type{
    if(self = [super init]){
        _rootVCType = type;
        _topViewController = topViewController;
    }
    return self;
}
- (void) display:(UIViewController*)viewController{
    switch (_rootVCType) {
        case KLRootVCTypeNormal:
            [_topViewController presentViewController:viewController animated:YES completion:nil];
            break;
        case KLRootVCTypeNavi:
            [_topViewController.navigationController pushViewController:viewController animated:YES];
            break;
        default:
            break;
    }
}

@end



@interface KLRouter()


@end

@implementation KLRouter

static KLRouter *SINGLETON = nil;

static bool isFirstAccess = YES;

#pragma mark - Public Method

+ (id)sharedInstance
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        isFirstAccess = NO;
        SINGLETON = [[super allocWithZone:NULL] init];    
    });
    
    return SINGLETON;
}

#pragma mark - Life Cycle

+ (id) allocWithZone:(NSZone *)zone
{
    return [self sharedInstance];
}

+ (id)copyWithZone:(struct _NSZone *)zone
{
    return [self sharedInstance];
}

+ (id)mutableCopyWithZone:(struct _NSZone *)zone
{
    return [self sharedInstance];
}

- (id)copy
{
    return [[KLRouter alloc] init];
}

- (id)mutableCopy
{
    return [[KLRouter alloc] init];
}

- (id) init
{
    if(SINGLETON){
        return SINGLETON;
    }
    if (isFirstAccess) {
        [self doesNotRecognizeSelector:_cmd];
    }
    self = [super init];
    return self;
}


#pragma mark -Router

+ (void)initialize
{
    _klUriRoute = [[NSDictionary alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"klUriRoute" ofType:@"plist"]];
}


- (void) _gotoViewController:(Class)vcCls withParams:(NSDictionary *)params{
    UIViewController *viewController = [self createViewController:vcCls params:params];
    [self gotoViewController:viewController];
}

- (void) gotoViewController:(NSString*)viewControllerName withParams:(NSDictionary *)params{
    return [self _gotoViewController:NSClassFromString(viewControllerName) withParams:params];
}

- (void) gotoViewController:(UIViewController *)viewController{
    if(viewController){
        KLTopViewController *topViewController = [self queryTopViewController];
        if(topViewController){
            [topViewController display:viewController];
        }
    }
}


- (void) replace:(UIViewController*)viewController WithViewController:(NSString *)viewControllerName withParams:(NSDictionary *)params{
//    UINavigationController *navi = viewController.navigationController;
//    NSAssert(navi, @"%@ does has navigation controller",viewControllerName);
    
    UIViewController *toViewController = [self createViewController:NSClassFromString(viewControllerName) params:params];
    if(!toViewController){
        return;
    }
    
    [self replace:viewController WithDstViewController:toViewController];
//    NSMutableArray *viewControllers = [[navi viewControllers] mutableCopy];
//    if([viewControllers containsObject:viewController]){
//        //use set will not animation because of fmnav
////        NSUInteger index = [viewControllers indexOfObject:viewController];
////        [viewControllers replaceObjectAtIndex:index withObject:toViewController];
////        [navi setViewControllers:viewControllers animated:YES];
//        
//        [navi popViewControllerAnimated:NO];
//        [navi pushViewController:toViewController animated:YES];
//    }
}
- (void) replace:(UIViewController*)srcViewController WithDstViewController:(UIViewController *)dstViewController{
    UINavigationController *navi = srcViewController.navigationController;
    NSAssert(navi, @"%@ does has navigation controller",srcViewController);
    
    UIViewController *toViewController = dstViewController;
    if(!toViewController){
        return;
    }
    
    NSMutableArray *viewControllers = [[navi viewControllers] mutableCopy];
    if([viewControllers containsObject:srcViewController]){
        //use set will not animation because of fmnav
        //        NSUInteger index = [viewControllers indexOfObject:viewController];
        //        [viewControllers replaceObjectAtIndex:index withObject:toViewController];
        //        [navi setViewControllers:viewControllers animated:YES];
        
        [navi popViewControllerAnimated:NO];
        [navi pushViewController:toViewController animated:YES];
    }
}


- (NSDictionary*) parseURIQueryString:(NSString*)query
{
    NSMutableDictionary* param = [[NSMutableDictionary alloc] initWithCapacity:2];
    NSArray* array = [query componentsSeparatedByString:@"&"];
    for(NSString* ss in array){
        NSArray* key = [ss componentsSeparatedByString:@"="];
        
        switch ([key count]) {
            case 1:
                [param setValue:nil forKey:[key objectAtIndex:0]];
                break;
            case 2:
                [param setValue:[key objectAtIndex:1] forKey:[key objectAtIndex:0]];
                break;
            default:
                break;
        }
    }
    return param;
}


+ (UIViewController*)createViewController:(NSString*)viewControllerName withParams:(NSDictionary*)params{
    return [[KLRouter sharedInstance] createViewController:NSClassFromString(viewControllerName) params:params];
}

- (Class)viewControllerCls:(NSString*)key{
    NSString *viewControllerName = [_klUriRoute objectForKey:key];
    return NSClassFromString(viewControllerName);
}


- (void) dismissViewController:(UIViewController *)viewController{
    if(viewController.navigationController){
        [viewController.navigationController popViewControllerAnimated:YES];
    }else{
        [viewController dismissViewControllerAnimated:YES completion:nil];
    }
}

- (BOOL)open:(NSString*)urlStr{
    return [self handleUrl:[NSURL URLWithString:urlStr]];
}
- (BOOL) handleUrl:(NSURL*)url{
    BOOL canHandle = NO;
    do{
        if(![self supportURL:[url scheme]]){
            break;
        }
        
        KLURL *klUrl = [[KLURL alloc]initWithURL:url];
        if(!klUrl){
            break;
        }
        
        Class  vcCls = [self viewControllerCls:klUrl.key];
        if(!vcCls){
            break;
        }
        
        canHandle = YES;
        [self _gotoViewController:vcCls withParams:klUrl.params];
        
    }while (NO);
    
    return canHandle;
}

- (UIViewController *)createViewController:(Class)vcCls params:(NSDictionary *)params{
    SEL CONTROLLER_CLASS_SELECTOR = sel_registerName("viewController:");
    SEL CONTROLLER_SELECTOR = sel_registerName("initWithParams:");
    UIViewController *controller = nil;
    Class controllerClass = vcCls;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
    if ([controllerClass respondsToSelector:CONTROLLER_CLASS_SELECTOR]) {
        controller = [controllerClass performSelector:CONTROLLER_CLASS_SELECTOR withObject:params];
    }
    else if ([controllerClass instancesRespondToSelector:CONTROLLER_SELECTOR]) {
        controller = [[controllerClass alloc] performSelector:CONTROLLER_SELECTOR withObject:params];
    }
#pragma clang diagnostic pop
    
    NSAssert(controller, @"viewController not implement viewController: or initWithParams: method");
    return controller;
}

- (KLTopViewController*) queryTopViewController{
    UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
    UIViewController *rootViewController = [window rootViewController];
    
    return [self _queryTopViewController:rootViewController];
    
//    UIViewController *topViewController = rootViewController;
//    KLRootVCType rootType = KLRootVCTypeNormal;
//    if(!rootViewController){
//    }
//
//    if([rootViewController isKindOfClass:[UINavigationController class]]){
//        topViewController = [(UINavigationController*)rootViewController topViewController];
//        rootType = KLRootVCTypeNavi;
//    }else if([rootViewController isKindOfClass:[UITabBarController class]]){
//        UITabBarController *tabBarViewController = (UITabBarController*)rootViewController;
//        UIViewController *selectedViewController = [tabBarViewController selectedViewController];
//        if(!selectedViewController && [[tabBarViewController viewControllers] count]){
//            selectedViewController = [tabBarViewController viewControllers][0];
//        }
//        if([selectedViewController isKindOfClass:[UINavigationController class]]){
//            topViewController = [(UINavigationController*)selectedViewController topViewController];
//
//            if(topViewController.presentedViewController){
//                topViewController = topViewController.presentedViewController;
//                if([topViewController isKindOfClass:[UINavigationController class]]){
//                    topViewController = [(UINavigationController*)topViewController topViewController];
//                }
//            }
//            rootType = KLRootVCTypeNavi;
//        }else{
//            topViewController = rootViewController;
//        }
//    }else{
//        topViewController = nil;
//    }
//
//    return [[KLTopViewController alloc]initWith:topViewController rootType:rootType];
}
- (KLTopViewController *) _queryTopViewController:(UIViewController *)viewController{
    UIViewController *presentedViewController = viewController.presentedViewController;
    KLTopViewController *outputViewController = nil;

    if(presentedViewController){
        outputViewController = [self _queryTopViewController:presentedViewController];
    }else if([viewController isKindOfClass:[UITabBarController class]]){
        UITabBarController *tabBarViewController = (UITabBarController*)viewController;
        UIViewController *selectedViewController = [tabBarViewController selectedViewController];
        if(!selectedViewController && [[tabBarViewController viewControllers] count]){
            selectedViewController = [tabBarViewController viewControllers][0];
        }
        outputViewController =  [self _queryTopViewController:selectedViewController];
    }else if([viewController isKindOfClass:[UINavigationController class]]){
        viewController = [(UINavigationController*)viewController topViewController];
        outputViewController = [self _queryTopViewController:viewController];
    }else{
        KLRootVCType rootType = KLRootVCTypeNormal;
        if(viewController.navigationController){
            rootType = KLRootVCTypeNavi;
        }
        outputViewController = [[KLTopViewController alloc]initWith:viewController rootType:rootType];
    }
    
    return outputViewController;
}



- (BOOL)supportURL:(NSString *)name{
    static NSArray *schemas = nil;
    if(!schemas){
        schemas = [KLRouter appUrlSchemes];
    }
    return [schemas containsObject:name];
}

+ (NSArray*)appUrlSchemes{
    
    NSMutableArray* appUrlSchemes = [NSMutableArray array];
    NSDictionary* infoDictionary = [[NSBundle mainBundle] infoDictionary];
    
    for (NSDictionary* dic in infoDictionary[@"CFBundleURLTypes"]) {
        NSString* appUrlScheme = dic[@"CFBundleURLSchemes"][0];
        [appUrlSchemes addObject:appUrlScheme];
    }
    
    return [appUrlSchemes copy];
}

@end
